const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 标签开头的正则 捕获的内容是标签名
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配标签结尾的 </div>
const attribute =
  /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; // 匹配属性的
const startTagClose = /^\s*(\/?)>/; // 匹配标签结束的 >
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; // 匹配 {{}} 表达式
export function parseHTML(html) {
  // 最终需要转换成一颗抽象语法树
  const ELEMENT_TYPE = 1;
  const TEXT_TYPE = 3;
  const stack = []; // 栈 用来存储元素节点
  let root; // 根节点
  let currentParent; // 当前父元素节点「栈的顶部是当前父元素节点」
  function createASTElement(tagName, attrs) {
    return {
      tag: tagName, // 标签名
      type: ELEMENT_TYPE,
      children: [],
      attrs,
      parent: null,
    };
  }
  function startfun(tagName, attrs) {
    // 创造一个元素节点
    let element = createASTElement(tagName, attrs);
    // 根节点
    if (!root) {
      root = element;
    }
    // 如果当前父元素存在
    if (currentParent) {
      element.parent = currentParent; // 让元素节点的父元素指向当前父元素
      currentParent.children.push(element); //让父亲记住自己的儿子
    }
    stack.push(element);
    // currentParent 为栈的顶部元素
    currentParent = element;
  }
  function charsfun(chars) {
    chars = chars.replace(/\s/g, "");
    if (!chars) {
      return;
    }
    // 文本直接添加到当前父元素的 children 数组中
    currentParent.children.push({
      type: TEXT_TYPE,
      text: chars,
      parent: currentParent,
    });
  }
  function endfun(tagName) {
    // 栈顶元素出栈
    stack.pop();
    // 栈顶元素的父元素就是当前父元素
    currentParent = stack[stack.length - 1];
  }
  // 截取html字符串 从指定位置开始截取
  function advance(len) {
    html = html.substring(len);
  }
  function handleStartTag() {
    let start = html.match(startTagOpen);
    if (start) {
      const match = {
        tagName: start[1],
        attrs: [],
      };
      // 前进 去掉已经解析的内容
      advance(start[0].length);
      // 解析属性
      let attr, end;
      // 如果还没匹配到标签闭合（例如 > 或 />），就持续匹配属性
      while (!(end = html.match(startTagClose))) {
        attr = html.match(attribute);
        if (!attr) break;

        // 前进光标
        advance(attr[0].length);

        // 收集属性
        match.attrs.push({
          name: attr[1],
          value: attr[3] || attr[4] || attr[5] || true, // 确保 value 不为 undefined
        });
      }

      // 匹配到结束标志（> 或 />）再前进
      if (end) {
        // 解析结束标签
        advance(end[0].length);
      }

      return match;
    }

    return false; // 不是开始标签
  }
  while (html) {
    let textEnd = html.indexOf("<"); //如果indexOf返回0 说明是标签开头，textEnd>0 说明是文本的结束
    if (textEnd === 0) {
      // 解析开始标签
      const startTag = handleStartTag();
      if (startTag) {
        startfun(startTag.tagName, startTag.attrs);
        continue;
      }
      // 解析结束标签
      let endTagMatch = html.match(endTag);
      if (endTagMatch) {
        endfun(endTagMatch[1]);
        advance(endTagMatch[0].length);
        continue;
      }
    }
    if (textEnd > 0) {
      // 文本内容
      let text = html.substring(0, textEnd);
      if (text) {
        charsfun(text);
        // 处理文本节点
        advance(text.length);
      }
    }
  }

  return root;
}
